---
title: "Swift 類型系統和可選類型"
description: "掌握 Swift 的類型系統和可選類型，從 JavaScript 角度理解類型安全、nil 處理和類型推斷。"
---

## 1. 介紹

### 為什麼類型系統很重要

Swift 的類型系統是其最強大的特性之一，提供編譯時安全性，防止許多常見的程式設計錯誤。作為 JavaScript 開發者，你習慣了動態類型，但 Swift 的靜態類型系統將幫助你編寫更可靠、更易維護的程式碼。

**主要學習目標：**
- 理解 Swift 的靜態類型系統 vs JavaScript 的動態類型
- 掌握可選類型和 nil 安全性
- 學習類型推斷和類型註解
- 探索類型轉換和類型檢查
- 培養類型安全程式設計實踐

## 2. 類型系統基礎

### 2.1 靜態 vs 動態類型

Swift 使用靜態類型，這意味著類型在編譯時檢查，與 JavaScript 的動態類型不同。

<UniversalEditor title="靜態 vs 動態類型" compare={true}>
```javascript !! js
// JavaScript - 動態類型
let value = "Hello";         // 字串
console.log(typeof value);   // "string"

value = 42;                  // 現在是數字
console.log(typeof value);   // "number"

value = true;                // 現在是布林值
console.log(typeof value);   // "boolean"

value = [1, 2, 3];          // 現在是陣列
console.log(typeof value);   // "object"

// 執行時類型檢查
function processValue(val) {
    if (typeof val === "string") {
        return val.toUpperCase();
    } else if (typeof val === "number") {
        return val * 2;
    } else {
        return "Unknown type";
    }
}

console.log(processValue("hello")); // "HELLO"
console.log(processValue(5));       // 10
console.log(processValue(true));    // "Unknown type"
```

```swift !! swift
// Swift - 靜態類型
var value: String = "Hello"         // 顯式字串類型
print(type(of: value))              // String

// 這些會導致編譯錯誤：
// value = 42                        // Error: Cannot assign value of type 'Int' to type 'String'
// value = true                      // Error: Cannot assign value of type 'Bool' to type 'String'
// value = [1, 2, 3]                // Error: Cannot assign value of type '[Int]' to type 'String'

// 編譯時類型檢查
func processValue(_ val: String) -> String {
    return val.uppercased()
}

func processValue(_ val: Int) -> Int {
    return val * 2
}

// 基於類型的函數重載
print(processValue("hello"))        // "HELLO"
print(processValue(5))              // 10
// processValue(true)               // Error: No matching function found
```
</UniversalEditor>

### 2.2 基本類型對比

Swift 比 JavaScript 有更具體的類型，提供更好的精度和安全性。

<UniversalEditor title="基本類型對比" compare={true}>
```javascript !! js
// JavaScript 基本類型
let stringValue = "Hello";          // String
let numberValue = 42;               // Number (浮點數)
let booleanValue = true;            // Boolean
let arrayValue = [1, 2, 3];         // Array
let objectValue = { name: "John" }; // Object
let nullValue = null;               // null
let undefinedValue = undefined;     // undefined

// 類型檢查
console.log(typeof stringValue);    // "string"
console.log(typeof numberValue);    // "number"
console.log(typeof booleanValue);   // "boolean"
console.log(typeof arrayValue);     // "object"
console.log(typeof objectValue);    // "object"
console.log(typeof nullValue);      // "object" (JavaScript 特性)
console.log(typeof undefinedValue); // "undefined"

// 類型強制轉換
console.log("5" + 3);               // "53" (字串連接)
console.log("5" - 3);               // 2 (數值減法)
console.log(true + 1);              // 2 (布林值轉數字)
```

```swift !! swift
// Swift 基本類型
let stringValue: String = "Hello"           // String
let intValue: Int = 42                      // Integer
let doubleValue: Double = 42.0              // Double (浮點數)
let floatValue: Float = 42.0                // Float (32位)
let booleanValue: Bool = true               // Boolean
let arrayValue: [Int] = [1, 2, 3]          // Int 陣列
let dictionaryValue: [String: String] = ["name": "John"] // Dictionary
let characterValue: Character = "A"         // 單個字元

// 類型檢查
print(type(of: stringValue))    // String
print(type(of: intValue))       // Int
print(type(of: doubleValue))    // Double
print(type(of: booleanValue))   // Bool
print(type(of: arrayValue))     // Array<Int>
print(type(of: dictionaryValue)) // Dictionary<String, String>

// 沒有隱式類型轉換
// print("5" + 3)               // Error: Cannot convert value of type 'Int' to expected argument type 'String'
print("5" + String(3))          // "53" (顯式轉換)
print(5 + 3)                    // 8 (數值加法)
```
</UniversalEditor>

## 3. 可選類型

### 3.1 理解可選類型

可選類型是 Swift 處理值缺失的方式，類似於 JavaScript 中的 `null` 和 `undefined`，但更安全。

<UniversalEditor title="可選類型介紹" compare={true}>
```javascript !! js
// JavaScript null/undefined 處理
let name = "John";
let age = 25;
let email = null;           // 明確沒有值
let phone = undefined;      // 未定義值

// 不安全訪問 - 可能導致執行時錯誤
function getLength(str) {
    return str.length;      // 如果 str 是 null/undefined 會拋出錯誤
}

// 安全訪問檢查
function safeGetLength(str) {
    if (str !== null && str !== undefined) {
        return str.length;
    }
    return 0;
}

// 現代 JavaScript 可選鏈
function modernGetLength(str) {
    return str?.length ?? 0;  // 安全訪問和空值合併
}

console.log(safeGetLength(name));   // 4
console.log(safeGetLength(email));  // 0
console.log(modernGetLength(phone)); // 0
```

```swift !! swift
// Swift 可選類型
let name: String = "John"
let age: Int = 25
let email: String? = nil           // 可選字串 (可以是 nil)
let phone: String? = nil           // 可選字串 (可以是 nil)

// 不安全訪問 - 如果 nil 會崩潰
// let emailLength = email.count   // Error: Value of optional type 'String?' must be unwrapped

// 安全訪問和可選綁定
func getLength(_ str: String?) -> Int {
    if let unwrappedStr = str {
        return unwrappedStr.count
    }
    return 0
}

// 安全訪問和空值合併
func modernGetLength(_ str: String?) -> Int {
    return str?.count ?? 0
}

print(getLength(name))      // 4
print(getLength(email))     // 0
print(modernGetLength(phone)) // 0
```
</UniversalEditor>

### 3.2 可選類型宣告和解包

Swift 提供多種安全處理可選類型的方式。

<UniversalEditor title="可選類型宣告和解包" compare={true}>
```javascript !! js
// JavaScript 可選模式
let optionalValue = null;
let defaultValue = "Default";

// 檢查 null/undefined
if (optionalValue !== null && optionalValue !== undefined) {
    console.log(optionalValue);
} else {
    console.log(defaultValue);
}

// 使用邏輯或 (但要小心假值)
let result = optionalValue || defaultValue;
console.log(result); // "Default"

// 使用空值合併 (現代 JavaScript)
let safeResult = optionalValue ?? defaultValue;
console.log(safeResult); // "Default"

// 可選鏈
let user = {
    profile: {
        name: "John",
        email: null
    }
};

console.log(user?.profile?.name);  // "John"
console.log(user?.profile?.email); // null
console.log(user?.profile?.email?.length); // undefined
```

```swift !! swift
// Swift 可選類型宣告和解包
let optionalValue: String? = nil
let defaultValue = "Default"

// 可選綁定 (if let)
if let unwrappedValue = optionalValue {
    print(unwrappedValue)
} else {
    print(defaultValue)
}

// Guard 語句
func processOptional(_ value: String?) {
    guard let unwrappedValue = value else {
        print("Value is nil")
        return
    }
    print("Processing: \(unwrappedValue)")
}

// 空值合併運算子
let result = optionalValue ?? defaultValue
print(result) // "Default"

// 可選鏈
struct Profile {
    let name: String
    let email: String?
}

struct User {
    let profile: Profile?
}

let user = User(profile: Profile(name: "John", email: nil))

print(user.profile?.name)           // Optional("John")
print(user.profile?.email)          // nil
print(user.profile?.email?.count)   // nil

// 強制解包 (謹慎使用)
let forcedValue = user.profile!.name // 如果 profile 是 nil 會崩潰
```
</UniversalEditor>

### 3.3 隱式解包可選類型

Swift 提供隱式解包可選類型，用於你確信值會存在的情況。

<UniversalEditor title="隱式解包可選類型" compare={true}>
```javascript !! js
// JavaScript - 沒有直接等價物，但類似模式
let config = {
    apiUrl: "https://api.example.com",
    timeout: 5000
};

// 假設 config 總是有這些屬性
function makeRequest() {
    // 我們假設 config.apiUrl 存在
    console.log(`Making request to ${config.apiUrl}`);
    
    // 但在實踐中仍需要檢查
    if (!config.apiUrl) {
        throw new Error("API URL is required");
    }
}

// 現代 JavaScript 預設參數
function safeMakeRequest(apiUrl = config.apiUrl) {
    if (!apiUrl) {
        throw new Error("API URL is required");
    }
    console.log(`Making request to ${apiUrl}`);
}
```

```swift !! swift
// Swift 隱式解包可選類型
let config: [String: String] = [
    "apiUrl": "https://api.example.com",
    "timeout": "5000"
]

// 隱式解包可選類型 - 假設值存在
let apiUrl: String! = config["apiUrl"]

func makeRequest() {
    // 可以直接使用 apiUrl 而無需解包
    print("Making request to \(apiUrl)")
    
    // 但如果 apiUrl 是 nil 會崩潰
    // 謹慎使用！
}

// 更安全的方法和常規可選類型
func safeMakeRequest() {
    guard let apiUrl = config["apiUrl"] else {
        print("API URL is required")
        return
    }
    print("Making request to \(apiUrl)")
}

// iOS 開發中的隱式解包可選類型
// @IBOutlet weak var label: UILabel!  // 假設 outlet 會被連接
```
</UniversalEditor>

## 4. 類型推斷

### 4.1 Swift 的類型推斷

Swift 通常可以自動確定類型，減少顯式類型註解的需要。

<UniversalEditor title="類型推斷" compare={true}>
```javascript !! js
// JavaScript 類型推斷 (執行時)
let message = "Hello";       // 推斷為字串
let count = 42;              // 推斷為數字
let isActive = true;         // 推斷為布林值
let items = [1, 2, 3];       // 推斷為陣列
let person = { name: "John" }; // 推斷為物件

// 類型可以在執行時改變
message = 123;               // 現在是數字
count = "forty-two";         // 現在是字串

// 函數參數類型不推斷
function processData(data) {
    // 沒有編譯時類型檢查
    return data.length;      // 對字串、陣列有效，但對數字無效
}

console.log(processData("hello")); // 5
console.log(processData([1, 2, 3])); // 3
console.log(processData(42)); // undefined (執行時錯誤)
```

```swift !! swift
// Swift 類型推斷 (編譯時)
let message = "Hello"        // 推斷為 String
let count = 42               // 推斷為 Int
let isActive = true          // 推斷為 Bool
let items = [1, 2, 3]        // 推斷為 [Int]
let person = ["name": "John"] // 推斷為 [String: String]

// 類型推斷後不能改變
// message = 123             // Error: Cannot assign value of type 'Int' to type 'String'
// count = "forty-two"       // Error: Cannot assign value of type 'String' to type 'Int'

// 函數參數類型從使用中推斷
func processData(_ data: String) -> Int {
    return data.count
}

func processData(_ data: [Int]) -> Int {
    return data.count
}

print(processData("hello"))  // 5
print(processData([1, 2, 3])) // 3
// processData(42)           // Error: No matching function found
```
</UniversalEditor>

### 4.2 類型註解

顯式類型註解可以使程式碼更清晰，幫助早期捕獲錯誤。

<UniversalEditor title="類型註解" compare={true}>
```javascript !! js
// JavaScript - 沒有靜態類型註解 (沒有 TypeScript)
let name = "John";
let age = 25;
let scores = [85, 90, 78];

// 使用 TypeScript (對比)
// let name: string = "John";
// let age: number = 25;
// let scores: number[] = [85, 90, 78];

// 沒有類型檢查的函數參數
function calculateAverage(numbers) {
    const sum = numbers.reduce((acc, num) => acc + num, 0);
    return sum / numbers.length;
}

// 執行時類型檢查
function safeCalculateAverage(numbers) {
    if (!Array.isArray(numbers)) {
        throw new Error("Input must be an array");
    }
    
    if (numbers.length === 0) {
        return 0;
    }
    
    const sum = numbers.reduce((acc, num) => {
        if (typeof num !== 'number') {
            throw new Error("All elements must be numbers");
        }
        return acc + num;
    }, 0);
    
    return sum / numbers.length;
}

console.log(calculateAverage([1, 2, 3, 4, 5])); // 3
console.log(safeCalculateAverage([1, 2, 3, 4, 5])); // 3
```

```swift !! swift
// Swift - 顯式類型註解
let name: String = "John"
let age: Int = 25
let scores: [Int] = [85, 90, 78]

// 顯式類型的函數
func calculateAverage(_ numbers: [Int]) -> Double {
    guard !numbers.isEmpty else { return 0.0 }
    
    let sum = numbers.reduce(0, +)
    return Double(sum) / Double(numbers.count)
}

// 可選返回類型的函數
func findFirstEven(_ numbers: [Int]) -> Int? {
    return numbers.first { $0 % 2 == 0 }
}

// 多返回類型的函數
func analyzeNumbers(_ numbers: [Int]) -> (min: Int, max: Int, average: Double) {
    let min = numbers.min() ?? 0
    let max = numbers.max() ?? 0
    let average = calculateAverage(numbers)
    
    return (min: min, max: max, average: average)
}

print(calculateAverage([1, 2, 3, 4, 5])) // 3.0
print(findFirstEven([1, 3, 5, 2, 4])) // Optional(2)
let analysis = analyzeNumbers([1, 2, 3, 4, 5])
print("Min: \(analysis.min), Max: \(analysis.max), Avg: \(analysis.average)")
```
</UniversalEditor>

## 5. 類型轉換

### 5.1 類型轉換方法

Swift 需要顯式類型轉換，防止意外的資料遺失。

<UniversalEditor title="類型轉換" compare={true}>
```javascript !! js
// JavaScript 類型轉換 (隱式和顯式)
let stringNum = "42";
let actualNum = 42;
let floatNum = 42.5;

// 隱式轉換 (可能有問題)
console.log(stringNum + actualNum);     // "4242" (字串連接)
console.log(stringNum - actualNum);     // 0 (數值減法)
console.log(actualNum + floatNum);      // 84.5 (數值加法)

// 顯式轉換
console.log(Number(stringNum));         // 42
console.log(String(actualNum));         // "42"
console.log(Boolean(actualNum));        // true
console.log(parseInt("42.5"));          // 42
console.log(parseFloat("42.5"));        // 42.5

// 陣列轉換
console.log(Array.from("hello"));       // ["h", "e", "l", "l", "o"]
console.log([...new Set([1, 2, 2, 3])]); // [1, 2, 3]

// 物件轉換
console.log(Object.keys({a: 1, b: 2})); // ["a", "b"]
console.log(Object.values({a: 1, b: 2})); // [1, 2]
```

```swift !! swift
// Swift 類型轉換 (僅顯式)
let stringNum = "42"
let actualNum = 42
let floatNum = 42.5

// 沒有隱式轉換
// print(stringNum + actualNum)         // Error: Cannot convert value of type 'Int' to expected argument type 'String'

// 顯式轉換
print(Int(stringNum) ?? 0)              // 42 (帶空值合併)
print(String(actualNum))                // "42"
print(Bool(actualNum))                  // true
print(Double(actualNum))                // 42.0

// 字串轉數字轉換
if let number = Int("42.5") {
    print(number)                       // 不會列印 (轉換失敗)
}
if let number = Double("42.5") {
    print(number)                       // 42.5
}

// 陣列轉換
let charArray = Array("hello")          // ["h", "e", "l", "l", "o"]
let uniqueArray = Array(Set([1, 2, 2, 3])) // [1, 2, 3]

// 字典轉換
let dict = ["a": 1, "b": 2]
print(Array(dict.keys))                 // ["a", "b"]
print(Array(dict.values))               // [1, 2]
```
</UniversalEditor>

### 5.2 類型檢查

Swift 提供編譯時類型檢查和執行時類型檢查功能。

<UniversalEditor title="類型檢查" compare={true}>
```javascript !! js
// JavaScript 類型檢查
function processValue(value) {
    // 執行時類型檢查
    if (typeof value === "string") {
        return value.toUpperCase();
    } else if (typeof value === "number") {
        return value * 2;
    } else if (Array.isArray(value)) {
        return value.length;
    } else if (typeof value === "object" && value !== null) {
        return Object.keys(value).length;
    } else {
        return "Unknown type";
    }
}

// 實例檢查
function checkInstance(value) {
    if (value instanceof Array) {
        return "Array";
    } else if (value instanceof Date) {
        return "Date";
    } else if (value instanceof RegExp) {
        return "RegExp";
    } else {
        return "Other";
    }
}

console.log(processValue("hello"));     // "HELLO"
console.log(processValue(5));           // 10
console.log(processValue([1, 2, 3]));   // 3
console.log(processValue({a: 1, b: 2})); // 2

console.log(checkInstance([1, 2, 3]));  // "Array"
console.log(checkInstance(new Date())); // "Date"
```

```swift !! swift
// Swift 類型檢查
func processValue(_ value: Any) -> String {
    // 執行時類型檢查和類型轉換
    if let stringValue = value as? String {
        return stringValue.uppercased()
    } else if let intValue = value as? Int {
        return String(intValue * 2)
    } else if let arrayValue = value as? [Any] {
        return String(arrayValue.count)
    } else if let dictValue = value as? [String: Any] {
        return String(dictValue.count)
    } else {
        return "Unknown type"
    }
}

// 使用 switch 語句的類型檢查
func checkType(_ value: Any) -> String {
    switch value {
    case is String:
        return "String"
    case is Int:
        return "Int"
    case is [Any]:
        return "Array"
    case is [String: Any]:
        return "Dictionary"
    default:
        return "Other"
    }
}

// 使用模式匹配的類型檢查
func processWithPattern(_ value: Any) -> String {
    switch value {
    case let string as String:
        return "String: \(string)"
    case let number as Int:
        return "Int: \(number)"
    case let array as [Any]:
        return "Array with \(array.count) elements"
    default:
        return "Unknown type"
    }
}

print(processValue("hello"))            // "HELLO"
print(processValue(5))                  // "10"
print(processValue([1, 2, 3]))          // "3"
print(processValue(["a": 1, "b": 2]))   // "2"

print(checkType("hello"))               // "String"
print(checkType(42))                    // "Int"
print(processWithPattern([1, 2, 3]))    // "Array with 3 elements"
```
</UniversalEditor>

## 6. 類型別名和自訂類型

### 6.1 類型別名

Swift 允許你建立類型別名以提高程式碼可讀性。

<UniversalEditor title="類型別名" compare={true}>
```javascript !! js
// JavaScript - 沒有直接類型別名，但類似模式
// 使用常數作為類型名
const UserId = String;
const UserAge = Number;
const UserEmail = String;

// 使用 JSDoc 進行類型文件
/**
 * @typedef {Object} User
 * @property {string} id
 * @property {string} name
 * @property {number} age
 * @property {string} email
 */

/**
 * @param {User} user
 * @returns {string}
 */
function formatUser(user) {
    return `${user.name} (${user.age}) - ${user.email}`;
}

// 使用 TypeScript (對比)
// type UserId = string;
// type UserAge = number;
// type UserEmail = string;

// interface User {
//     id: UserId;
//     name: string;
//     age: UserAge;
//     email: UserEmail;
// }

const user = {
    id: "123",
    name: "John",
    age: 25,
    email: "john@example.com"
};

console.log(formatUser(user));
```

```swift !! swift
// Swift 類型別名
typealias UserId = String
typealias UserAge = Int
typealias UserEmail = String

// 在結構體中使用類型別名
struct User {
    let id: UserId
    let name: String
    let age: UserAge
    let email: UserEmail
}

// 使用類型別名的函數
func formatUser(_ user: User) -> String {
    return "\(user.name) (\(user.age)) - \(user.email)"
}

// 複雜類型的類型別名
typealias UserList = [User]
typealias UserDictionary = [UserId: User]
typealias UserFilter = (User) -> Bool

// 使用複雜類型別名
func filterUsers(_ users: UserList, by filter: UserFilter) -> UserList {
    return users.filter(filter)
}

func findUser(by id: UserId, in users: UserDictionary) -> User? {
    return users[id]
}

let user = User(
    id: "123",
    name: "John",
    age: 25,
    email: "john@example.com"
)

print(formatUser(user))

// 閉包的類型別名
typealias CompletionHandler = (Result<User, Error>) -> Void
typealias NetworkCallback = (Data?, Error?) -> Void
```
</UniversalEditor>

## 7. 練習

### 練習 1: 可選類型處理

<UniversalEditor title="練習 1: 可選類型處理" compare={true}>
```javascript !! js
// JavaScript 可選類型處理練習
function processUserData(userData) {
    // 處理可能缺失的使用者資料
    const name = userData?.name || "Unknown";
    const age = userData?.age || 0;
    const email = userData?.email || "No email";
    
    return {
        displayName: name,
        ageGroup: age < 18 ? "Minor" : age < 65 ? "Adult" : "Senior",
        hasEmail: email !== "No email"
    };
}

function safeStringLength(str) {
    // 處理 null/undefined 字串
    if (str === null || str === undefined) {
        return 0;
    }
    return str.length;
}

function findFirstPositive(numbers) {
    // 找到第一個正數或返回 null
    for (let num of numbers) {
        if (num > 0) {
            return num;
        }
    }
    return null;
}

// 測試函數
console.log(processUserData({ name: "John", age: 25, email: "john@example.com" }));
console.log(processUserData({ name: "Jane", age: 16 }));
console.log(processUserData(null));

console.log(safeStringLength("hello")); // 5
console.log(safeStringLength(null)); // 0

console.log(findFirstPositive([-1, -2, 3, -4, 5])); // 3
console.log(findFirstPositive([-1, -2, -3])); // null
```

```swift !! swift
// Swift 可選類型處理練習
struct UserData {
    let name: String?
    let age: Int?
    let email: String?
}

func processUserData(_ userData: UserData?) -> (displayName: String, ageGroup: String, hasEmail: Bool) {
    // 處理可能缺失的使用者資料
    let name = userData?.name ?? "Unknown"
    let age = userData?.age ?? 0
    let email = userData?.email
    
    let ageGroup: String
    if age < 18 {
        ageGroup = "Minor"
    } else if age < 65 {
        ageGroup = "Adult"
    } else {
        ageGroup = "Senior"
    }
    
    return (
        displayName: name,
        ageGroup: ageGroup,
        hasEmail: email != nil
    )
}

func safeStringLength(_ str: String?) -> Int {
    // 處理可選字串
    return str?.count ?? 0
}

func findFirstPositive(_ numbers: [Int]) -> Int? {
    // 找到第一個正數或返回 nil
    return numbers.first { $0 > 0 }
}

// 測試函數
let user1 = UserData(name: "John", age: 25, email: "john@example.com")
let user2 = UserData(name: "Jane", age: 16, email: nil)
let user3: UserData? = nil

print(processUserData(user1))
print(processUserData(user2))
print(processUserData(user3))

print(safeStringLength("hello")) // 5
print(safeStringLength(nil)) // 0

print(findFirstPositive([-1, -2, 3, -4, 5])) // Optional(3)
print(findFirstPositive([-1, -2, -3])) // nil
```
</UniversalEditor>

### 練習 2: 類型轉換和檢查

<UniversalEditor title="練習 2: 類型轉換和檢查" compare={true}>
```javascript !! js
// JavaScript 類型轉換練習
function convertToNumber(value) {
    const num = Number(value);
    return isNaN(num) ? null : num;
}

function convertToString(value) {
    if (value === null || value === undefined) {
        return "null";
    }
    return String(value);
}

function validateUserInput(input) {
    const errors = [];
    
    if (typeof input.name !== "string" || input.name.trim() === "") {
        errors.push("Name must be a non-empty string");
    }
    
    if (typeof input.age !== "number" || input.age < 0 || input.age > 150) {
        errors.push("Age must be a number between 0 and 150");
    }
    
    if (typeof input.email !== "string" || !input.email.includes("@")) {
        errors.push("Email must be a valid email address");
    }
    
    return errors;
}

// 測試函數
console.log(convertToNumber("42")); // 42
console.log(convertToNumber("abc")); // null
console.log(convertToNumber("42.5")); // 42.5

console.log(convertToString(42)); // "42"
console.log(convertToString(null)); // "null"
console.log(convertToString([1, 2, 3])); // "1,2,3"

const validInput = { name: "John", age: 25, email: "john@example.com" };
const invalidInput = { name: "", age: "25", email: "invalid-email" };

console.log(validateUserInput(validInput)); // []
console.log(validateUserInput(invalidInput)); // ["Name must be a non-empty string", "Age must be a number between 0 and 150", "Email must be a valid email address"]
```

```swift !! swift
// Swift 類型轉換練習
func convertToNumber(_ value: String) -> Int? {
    return Int(value)
}

func convertToString(_ value: Any) -> String {
    if let optionalValue = value as? Optional<Any> {
        return "nil"
    }
    return String(describing: value)
}

struct UserInput {
    let name: String
    let age: Int
    let email: String
}

func validateUserInput(_ input: UserInput) -> [String] {
    var errors: [String] = []
    
    if input.name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
        errors.append("Name must be a non-empty string")
    }
    
    if input.age < 0 || input.age > 150 {
        errors.append("Age must be a number between 0 and 150")
    }
    
    if !input.email.contains("@") {
        errors.append("Email must be a valid email address")
    }
    
    return errors
}

// 測試函數
print(convertToNumber("42")) // Optional(42)
print(convertToNumber("abc")) // nil
print(convertToNumber("42.5")) // nil (Int 轉換對小數失敗)

print(convertToString(42)) // "42"
print(convertToString(nil as String?)) // "nil"
print(convertToString([1, 2, 3])) // "[1, 2, 3]"

let validInput = UserInput(name: "John", age: 25, email: "john@example.com")
let invalidInput = UserInput(name: "", age: 200, email: "invalid-email")

print(validateUserInput(validInput)) // []
print(validateUserInput(invalidInput)) // ["Name must be a non-empty string", "Age must be a number between 0 and 150", "Email must be a valid email address"]
```
</UniversalEditor>

## 8. 關鍵要點

### 8.1 類型系統優勢

| 特性 | JavaScript | Swift | 優勢 |
|---|---|---|---|
| **類型安全** | 執行時檢查 | 編譯時檢查 | 在執行前捕獲錯誤 |
| **性能** | 動態分發 | 靜態分發 | 更好的性能 |
| **工具支援** | 有限的 IDE 支援 | 豐富的 IDE 支援 | 更好的自動完成和重構 |
| **文件** | 註釋/JSDoc | 類型註解 | 自文件化程式碼 |
| **重構** | 容易出錯 | 安全 | 自信的程式碼更改 |

### 8.2 可選類型最佳實踐

1. **使用可選類型表示缺失值**: 不要使用哨兵值如 `-1` 或 `""`
2. **優先使用可選綁定**: 使用 `if let` 和 `guard let` 而不是強制解包
3. **使用空值合併**: `??` 運算子提供預設值
4. **避免強制解包**: 只在絕對確定時使用 `!`
5. **使用可選鏈**: `?.` 安全屬性訪問
6. **返回可選類型**: 當函數可能沒有結果時

### 8.3 類型安全最佳實踐

1. **使用類型註解**: 顯式類型提高程式碼清晰度
2. **利用類型推斷**: 當明顯時讓 Swift 推斷類型
3. **使用類型別名**: 複雜類型和更好的可讀性
4. **優先強類型**: 使用具體類型而不是 `Any`
5. **安全處理可選類型**: 始終考慮 nil 情況
6. **使用類型檢查**: `is` 和 `as?` 進行執行時類型檢查

### 8.4 常見陷阱

1. **強制解包**: 不檢查 nil 就使用 `!`
2. **忽略可選類型**: 不處理 nil 的可能性
3. **類型 Any**: 在具體類型更好時使用 `Any`
4. **隱式轉換**: 期望自動類型轉換
5. **執行時錯誤**: 不有效使用編譯時類型檢查

## 9. 下一步

在下一個模組中，我們將詳細探索函數和閉包，包括：
- 函數類型和高階函數
- 閉包語法和捕獲語義
- 函數重載和預設參數
- Swift 中的函數式程式設計模式

這個 Swift 類型系統基礎將為你準備更高級的概念，幫助你編寫更安全、更可靠的程式碼。 